/**
 * Collaborative Story Development Web Application (CSDApp) 
 * Copyright Anton Strack 2014
 *
 * This file is part of Collaborative Story Development Application (CSDApp).
 *
 * CSDApp is free software: you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * CSDApp is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * CSDApp. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package csdwa;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Anton Strack
 */
public class CommentController extends PostController {

    private final String VIEW_LIST = "/comment/index.jsp";
    private final String VIEW_VIEW = "/comment/view.jsp";
    private final String VIEW_CREATE = "/comment/create.jsp";
    private final String VIEW_UPDATE = "/comment/update.jsp";
    private final String VIEW_DELTE = "/comment/delete.jsp";

    public CommentController(Connection conn) {
        super(conn);
    }

    /**
     * This method primarily handles form related requests.
     *
     * @param request the request object
     * @return an updated request object sufficient to complete the request.
     */
    @Override
    public CsdwaRequest handlePostRequest(CsdwaRequest request) {
        String form = request.getFormId();
        System.out.println("entered handle post for commentController");
        if (!form.isEmpty()) {
            System.out.println("form name is:" + form);
            request.setPrimaryResourceId(request.getParameter("postId"));
            if (form.equalsIgnoreCase("create-comment")) {
                request.removeFormId();
                request = handleCreate(request);
            } else if (form.equalsIgnoreCase("update-comment")) {
                System.out.println("sending request to handleUpdate()");
                request.removeFormId();
                request = handleUpdate(request);
            } else if (form.equalsIgnoreCase("delete-comment")) {
                request.removeFormId();
                request = handleDelete(request);
            }

        }
        return request;
    }

    /**
     * This method handles get requests. It accepts the primaryResouce and
     * primaryAction as variables to allow routing from the handleGetRequest
     * method.
     *
     * @param primaryResource the primary resource that will handle the request
     * @param primaryAction the primary action on the resource.
     * @param request the request object
     * @return
     */
    @Override
    public CsdwaRequest handleGetRequest(CsdwaRequest request) {
        String primaryAction = request.getPrimaryActionTypeName();
        String primaryResource = request.getPrimaryResourceTypeName();
        int id = request.getPrimaryResourceId();

        if ("comment".equalsIgnoreCase(primaryResource)) {
            if ("view".equalsIgnoreCase(primaryAction) && id != 0) {
                CommentDao pdao = new CommentDao(conn);
                pdao.setUseRelatedMarkers(true);
                pdao.selectBeanById(id);
                request.removeAttribute("bean");
                request.setAttribute("bean", pdao.getBeans().get(0));
                request.setView(VIEW_VIEW);
            } else if ("update".equalsIgnoreCase(primaryAction) && id != 0) {
                CommentDao pdao = new CommentDao(conn);
                pdao.selectBeanById(id);
                Comment comment = pdao.getBean();
                /* Store the bean in a session so that the it is available to the jsp page and also post update handler on post submit. This way it can compare the post bean values to the original bean values. Doing so will mean that only the columns changed will be sent to the database to be updated.
                 */
                int parentId = comment.getParentId();
                int parentTypeId = comment.getParentResourceTypeId();
                request.setAttribute("parentTypeId", parentTypeId);
                request.setAttribute("parentId", parentId);
                request.removeSessionAttribute("bean");
                request.setSessionAttribute("bean", comment);
                request.setView(VIEW_UPDATE);
            } else if ("create".equalsIgnoreCase(primaryAction)) {
                request.setAttribute("stateId", 1); // temp
                request.setAttribute("stateName", "Draft"); // temp
                request.setView(VIEW_CREATE);
            } else if ("delete".equalsIgnoreCase(primaryAction)) {
                CommentDao cdao = new CommentDao(conn);
                cdao.selectBeanById(id);
                Comment comment = cdao.getBean();

                int parentId = comment.getParentId();
                int parentTypeId = comment.getParentResourceTypeId();
                request.setAttribute("parentTypeId", parentTypeId);
                request.setAttribute("parentId", parentId);
                request.setAttribute("bean", comment);
                int commentTypeId = cdao.getBean().getResourceTypeId();
                cdao.clearDaoBeans();
                cdao.selectBeansByParent(id, commentTypeId);
                List<Comment> comments = cdao.getBeans();
                if (comments.isEmpty() == false) {
                    request.setAttribute("comments", comments);
                }
                request.setView(VIEW_DELTE);
                // also need to selecte the participating relationships and comments to send along for the list of cascading deletes
                /*
                 * Go to a delete page that will inform the user of what else will be deleted and thus ask the user to confirm deletion.
                 */
            } else {// index by default
                CommentDao pdao = new CommentDao(conn);
                pdao.setUseRelatedMarkers(true);
                pdao.selectBeans();
                request.setAttribute("beans", pdao.getBeans());
                request.setView(VIEW_LIST);
            }
        }
        return request;
    }

    /**
     * This method saves the bean to the database.
     *
     * @param request the create request object containing the form values.
     * @return the request object with the requestResultMessage object set to
     * indicate the result
     */
    private CsdwaRequest handleCreate(CsdwaRequest request) {
        User user = request.getCurrentUser();
        Timestamp timestamp = new Timestamp(new Date().getTime());
        // Create validators to use for validation
        CsdwaValidator isNotEmpty = new IsNotEmpty();
        CsdwaValidator isNumeric = new IsNumeric();
        // add request parameter values to the object to test validation
        ValidatorValue postName = new ValidatorValue(request.getParameter("postName"), "Comment Name");
        ValidatorValue postSection = new ValidatorValue(request.getParameter("postSection"), "Comment Section");
        ValidatorValue postBody = new ValidatorValue(request.getParameter("postBody"), "Comment Body");
        ValidatorValue parentId = new ValidatorValue(request.getParameter("parentId"), "Comment ParentID");
        ValidatorValue parentTypeId = new ValidatorValue(request.getParameter("parentTypeId"), "Comment Parent Type ID");
        // the the validators to the validation values
        postName.addValidator(isNotEmpty);
        postSection.addValidator(isNotEmpty);
        postBody.addValidator(isNotEmpty);
        parentId.addValidator(isNumeric).addValidator(isNotEmpty);
        parentTypeId.addValidator(isNumeric).addValidator(isNotEmpty);
        // isValid the values.
        if (postName.isValid() && postSection.isValid() && postBody.isValid() && parentId.isValid() && parentTypeId.isValid()) {
            Comment post = ResourceFactory.makeComment();
            post.setName(postName.getString());
            post.setSection(postSection.getString());
            post.setBody(postBody.getString());
            post.setStateId(1);
            post.setParentResourceTypeId(parentTypeId.getInteger());
            post.setParentId(parentId.getInteger());
            post.setParentCommentedDate(timestamp);// need to set this to the post updated date
            post.setUpdatedById(user.getId());
            post.setCreatedById(user.getId());
            post.setCreatedDate(timestamp);
            post.setUpdatedDate(timestamp);
            CommentDao pdao = new CommentDao(conn);
            int result = pdao.insertBean(post);// id
            System.out.println("result for comment insert is:" + result);
            if (result >= 0) {

                //  String resourceName = ResourceRequestDelegator.getResourceName(commentedPostTypeId);
                //               request.setSecondaryResourceTypeName("comment");
//                request.setSecondaryResourceId(result);
                request.setPrimaryActionTypeName("view");
                request.setPrimaryResourceTypeName(InfoAggregator.getInstance().getResourceTypeName(parentTypeId.getInteger()));
                request.setPrimaryResourceId(parentId.getInteger());
                request.setMethod("GET");
                request = getResourceRequestDelegator().processRequest(request);
            } else {
                request.setMessage("There was an error saving the comment to the database.");
                request.setMessageType("error");
                request.setPrimaryActionTypeName("view");
                request.setPrimaryResourceTypeName(InfoAggregator.getInstance().getResourceTypeName(parentTypeId.getInteger()));
                request.setPrimaryResourceId(parentId.getInteger());
                request.setMethod("GET");
                request = getResourceRequestDelegator().processRequest(request);
            }
        } else {
            request.setMessage(postName.getErrorMessage() + postSection.getErrorMessage() + postBody.getErrorMessage() + parentId.getErrorMessage() + parentTypeId.getErrorMessage());
            request.setMessageType("info");
            request.setPrimaryActionTypeName("view");
            request.setPrimaryResourceTypeName(InfoAggregator.getInstance().getResourceTypeName(parentTypeId.getInteger()));
            request.setPrimaryResourceId(parentId.getInteger());
            request.setMethod("GET");
            request = getResourceRequestDelegator().processRequest(request);
        }
        return request;
    }

    /**
     * // not sure if comments can be updated or not yet * This method handles
     * updating the bean. If the bean to be updated was properly set as a bean
     * in the session, then this method will instruct the dao to update only the
     * fields that were changed and thus reduce message size.
     *
     * @param request the update request object
     * @return a request object with the requestResultMessage object set to
     * indicate the update result.
     */
    private CsdwaRequest handleUpdate(CsdwaRequest request) {
        int id = request.getPrimaryResourceId();
        User user = (User) request.getSessionAttribute("user");
        Timestamp timestamp = new Timestamp(new Date().getTime()); // validate fields String postName =

        // Create validators to use for validation
        CsdwaValidator isNotEmpty = new IsNotEmpty();
        CsdwaValidator isNumeric = new IsNumeric();
        // add request parameter values to the object to test validation
        ValidatorValue postName = new ValidatorValue(request.getParameter("postName"), "Comment Name");
        ValidatorValue postSection = new ValidatorValue(request.getParameter("postSection"), "Comment Section");
        ValidatorValue postBody = new ValidatorValue(request.getParameter("postBody"), "Comment Body");
        ValidatorValue parentId = new ValidatorValue(request.getParameter("parentId"), "Comment ParentID");
        ValidatorValue parentTypeId = new ValidatorValue(request.getParameter("parentTypeId"), "Comment Parent Type ID");
        // the the validators to the validation values
        postName.addValidator(isNotEmpty);
        postSection.addValidator(isNotEmpty);
        postBody.addValidator(isNotEmpty);
        parentId.addValidator(isNumeric).addValidator(isNotEmpty);
        parentTypeId.addValidator(isNumeric).addValidator(isNotEmpty);
        if (postName.isValid() && postSection.isValid() && postBody.isValid() && parentId.isValid() && parentTypeId.isValid()) {
            CommentDao pdao = new CommentDao(conn);
            Comment comment = (Comment) request.getSessionAttribute("bean");
            StringBuilder sb = new StringBuilder();
            if (comment == null) {
                comment =
                        ResourceFactory.makeComment();// if the original post didn't get stored
                //in the session, then create a new one.
            }
            if (comment.getName().equals(postName.getValue()) == false) {
                sb.append("Name");
            }
            if (comment.getSection().equals(postSection.getValue()) == false) {
                if (sb.length()
                        > 0) {
                    sb.append(", ");
                }
                sb.append("Section");
            }
            if (comment.getBody().equals(postBody.getValue()) == false) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append("Body");
            }
//            if (comment.getStateId()
//                    != Integer.parseInt(postState)) {
//                if (sb.length() > 0) {
//                    sb.append(", ");
//                }
//                sb.append("StateID");
//            }


            // always set updated by id
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append("UpdatedByID"); // always set updated date if (sb.length() > 0)
            {
                sb.append(", ");
            }
            sb.append("UpdatedDate");

            // update the original bean with all the values from the form submit
            comment.setName(postName.getString());
            comment.setSection(postSection.getString());
            comment.setBody(postBody.getString());
            comment.setStateId(comment.getStateId());
            comment.setUpdatedById(user.getId());
            comment.setUpdatedDate(timestamp);

            // declare the columns to update.
            pdao.setColumnsToUpdate(sb.toString());
            System.out.println("ColumnsToUpdate are:" + sb.toString());

            int result = pdao.updateBean(comment);
            System.out.println("result for comment update is:" + result);
            request.removeAttribute("formSubmit");
            if (result >= 0) {
                request.setMessage("Comment successfully updated.");
                request.setMessageType("info");
                request.setPrimaryActionTypeName("view");
                request.setPrimaryResourceTypeName(InfoAggregator.getInstance().getResourceTypeName(parentTypeId.getInteger()));
                request.setPrimaryResourceId(parentId.getInteger());
                request.setMethod("GET");
                request = getResourceRequestDelegator().processRequest(request);
            } else {
                request.setMessage("There was an error update the comment to the database.");
                request.setMessageType("error");
                request.setPrimaryActionTypeName("update");
                request.setPrimaryResourceTypeName("comment");
                request.setPrimaryResourceId(id);
                request = handleGetRequest(request);
            }
        } else {
            request.setMessage(postName.getErrorMessage() + postSection.getErrorMessage() + postBody.getErrorMessage() + parentId.getErrorMessage() + parentTypeId.getErrorMessage());
            request.setMessageType("info");
            request.setPrimaryActionTypeName("update");
            request.setPrimaryResourceTypeName("comment");
            request.setPrimaryResourceId(id);
            request = handleGetRequest(request);
        }
        return request;
    }

    /**
     * This method handles deleting the specific bean from the database. This
     * method handles the cascading deletes of all dependant resources.
     *
     * @param request the delete request object.
     * @param id the id of the bean to delete
     * @return a request object with a requestResultMessage object specifying
     * the result.
     */
    private CsdwaRequest handleDelete(CsdwaRequest request) {
        // validate fields
        boolean allowDelete = false; // String parentId = request.getParameter("parentId");
        // Create validators to use for validation
        CsdwaValidator isNotEmpty = new IsNotEmpty();
        CsdwaValidator isNumeric = new IsNumeric();
        // add request parameter values to the object to test validation
        ValidatorValue id = new ValidatorValue(request.getParameter("postId"), "ID");
        ValidatorValue parentId = new ValidatorValue(request.getParameter("parentId"), "ParentID");
        ValidatorValue parentTypeId = new ValidatorValue(request.getParameter("parentTypeId"), "Parent Type ID");
        // the the validators to the validation values

        id.addValidator(isNumeric).addValidator(isNotEmpty);
        parentId.addValidator(isNumeric).addValidator(isNotEmpty);
        parentTypeId.addValidator(isNumeric).addValidator(isNotEmpty);
        if (id.isValid() && parentId.isValid() && parentTypeId.isValid()) {

            try {
                Connection conn = this.conn;
                conn.setAutoCommit(false);// enter transaction mode
                Savepoint delete = conn.setSavepoint("delete-comment_" + id);
                CommentDao pdao = new CommentDao(conn);

                Comment post = ResourceFactory.makeComment();
                post.setId(id.getInteger());

                String parentResourceName = InfoAggregator.getInstance().getResourceTypeName(parentTypeId.getInteger());
                // check for comments // - delete comments
                CommentDao cdao = new CommentDao(conn);
                cdao.selectBeansByParent(post.getId(), post.getResourceTypeId());
                this.deleteDependants(cdao);

                List<Comment> comments = cdao.getBeans();
                if (comments.isEmpty()) {
                    allowDelete = true;
                } else {
                    int continueDelete = 1;
                    int i = 0;
                    int commentsSize = comments.size();
                    while (continueDelete == 1 && i < commentsSize) {
                        continueDelete = cdao.deleteBean(comments.get(i));
                        i++;
                        if (continueDelete == 1) {
                            allowDelete = true;
                        }
                    }
                }

                if (allowDelete == true) {
                    int result = pdao.deleteBean(post);
                    if (result > 0) { // conn.commit();
                        conn.setAutoCommit(true);// reset  commit mode to auto and commit the transaction since the deletion worked  correctly.

                        request.setMessage("Comment was successfully deleted.");
                        request.setMessageType("success");
                        request.setPrimaryActionTypeName("view");
                        request.setPrimaryResourceTypeName(parentResourceName);
                        request.setPrimaryResourceId(parentId.getInteger());
                        request.setMethod("GET");
                        request = ResourceRequestDelegator.processRequest(request);

                    } else {
                        conn.rollback(delete); // delete failed so roll back connection
                        conn.setAutoCommit(true);// reset commit mode to auto
                        request.setMessage("There was an error trying to delete the plot  from the database.");
                        request.setMessageType("error");
                        request.setPrimaryActionTypeName("view");
                        request.setPrimaryResourceTypeName(parentResourceName);
                        request.setPrimaryResourceId(parentId.getInteger());
                        request.setMethod("GET");
                        request = ResourceRequestDelegator.processRequest(request);
                    }
                } else {
                    conn.rollback(delete); // delete failed so roll back connection
                    conn.setAutoCommit(true);// reset commit mode to auto
                    request.setMessage("A dependant resource could not be deleted. Deletion aborted.");
                    request.setMessageType("error");
                    request.setPrimaryActionTypeName("view");
                    request.setPrimaryResourceTypeName(parentResourceName);
                    request.setPrimaryResourceId(parentId.getInteger());
                    request.setMethod("GET");
                    request = ResourceRequestDelegator.processRequest(request);
                }
            } catch (SQLException ex) {
                Logger.getLogger(PlotController.class.getName()).log(Level.SEVERE, null,
                        ex);
            }
        } else {
            request.setMessage("There was an error with the delete request. Could not determine the comment ID.");
            request.setMessageType("error");
            request.setPrimaryActionTypeName("list");
            request.setPrimaryResourceTypeName("site");
            request.setMethod("GET");
            request = ResourceRequestDelegator.processRequest(request);
        }
        return request;
    }
}
